package com.ppp.poi.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.opencsv.CSVWriter;
import com.ppp.poi.bean.base.WorkThreadPool;
import com.ppp.poi.bean.dto.PoiParam;
import com.ppp.poi.bean.entity.Records;
import com.ppp.poi.bean.entity.Region;
import com.ppp.poi.bean.entity.User;
import com.ppp.poi.bean.result.DistrictResult;
import com.ppp.poi.bean.result.PoiResult;
import com.ppp.poi.common.AppConstant;
import com.ppp.poi.common.Parameter;
import com.ppp.poi.common.exception.AppSimpleException;
import com.ppp.poi.common.utils.NumericConvertUtils;
import com.ppp.poi.dao.RecordsDao;
import com.ppp.poi.utils.GpsUtils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.mail.Message.RecipientType;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import javax.mail.util.ByteArrayDataSource;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;

/**
 * @author Wu Jin
 * @create 2020-01-19
 */
@Slf4j
@Service
public class GaodeService {

  @Autowired
  private Parameter parameter;

  @Autowired
  private HttpService httpService;

  @Autowired
  private UserService userService;

  @Autowired
  private RecordsDao recordsDao;

  private Executor executor = WorkThreadPool.get();

  private Executor sender = WorkThreadPool.getSender();

  /**
   * 获取行政区域adcode
   */
  public List<String> getAdCode(String adCodeProvince) {
    String formatUrl = String.format(AppConstant.DISTRICT_URL_BASE, getKey(), adCodeProvince);
    DistrictResult districtResult = httpService.doGetForPojo(formatUrl, DistrictResult.class);
    List<Region> districts = districtResult.getDistricts().get(0).getDistricts();
    return districts.stream().map(d -> d.getAdcode()).collect(Collectors.toList());
  }

  /**
   * 坐标切割
   */
  public List<List<String>> burnloc(PoiParam poiParam) {
    List<List<String>> result = new ArrayList<>();
    Double lng1Double = Double.valueOf(poiParam.getLng1()) * 100;
    Double lat1Double = Double.valueOf(poiParam.getLat1()) * 100;
    Double lng2Double = Double.valueOf(poiParam.getLng2()) * 100;
    Double lat2Double = Double.valueOf(poiParam.getLat2()) * 100;
    for (int i = lng1Double.intValue(); i < lng2Double.intValue() + 1; i++) {
      for (int j = lat2Double.intValue(); j < lat1Double.intValue() + 1; j++) {
        result.add(Arrays.asList(String.format("%.2f", i / 100.0), String.format("%.2f", j / 100.0)));
      }
    }
    return result;
  }

  private String getKey() {
    return "787f1d270b86c546795c1dd7b40d0cf0";
  }

  public void search(PoiParam poiParam) {
    String url = "";
    if (StringUtils.isEmpty(poiParam.getPolygon()) && !StringUtils.isEmpty(poiParam.getCitycode()) && !"null"
        .equalsIgnoreCase(poiParam.getCitycode())) {
      url = AppConstant.KEYWORD_URL;
      poiParam.getParamMap().add("key", getKey());
      poiParam.getParamMap().add("types", poiParam.getTypes());
      poiParam.getParamMap().add("city", poiParam.getCitycode());
      poiParam.getParamMap().add("keywords", poiParam.getKeyword());
    } else if (!StringUtils.isEmpty(poiParam.getPolygon())) {
      url = AppConstant.POLIYGON_URL_BASE;
      poiParam.getParamMap().add("polygon", poiParam.getPolygon());
      poiParam.getParamMap().add("key", getKey());
      poiParam.getParamMap().add("types", poiParam.getTypes());
      poiParam.getParamMap().add("keywords", poiParam.getKeyword());
    } else {
      throw new AppSimpleException("参数不全");
    }
    User u = (User) AppConstant.get("user");
    if (u != null) {
      if (!StringUtils.isEmpty(poiParam.getEmail())) {
        u.setEmail(poiParam.getEmail());
      }
      if (!StringUtils.isEmpty(poiParam.getMobile())) {
        u.setMobile(poiParam.getMobile());
      }
      userService.update(u);
      poiParam.setUserId(u.getId());
    }
    String finalUrl = url;
    sender.execute(() -> {
      try {
        doSearch(finalUrl, poiParam);
      } catch (IOException e) {
        e.printStackTrace();
      }
    });
  }

  public void doSearch(String url, PoiParam poiParam) throws IOException {
    String[] headers = poiParam.getHeaders().split(",");
    List<CompletableFuture<PoiResult>> list = new ArrayList<>(20);
    List<JSONObject> data = new ArrayList<>();
    File poi = File.createTempFile("poi", ".csv");
    FileOutputStream out = new FileOutputStream(poi);
    out.write(new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF});
    Writer writer = new OutputStreamWriter(out, "UTF-8");

    // 暂时取它20页
    for (int i = 0; i < 20; i++) {
      MultiValueMap<String, String> map = new LinkedMultiValueMap<>(poiParam.getParamMap());
      map.set("page", (i + 1) + "");
      String tempUrl = url;
      list.add(CompletableFuture.supplyAsync(() -> httpService.doPostForPojo(tempUrl, map, PoiResult.class), executor));
    }
    try {
      CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()]))
          .whenComplete((aVoid, throwable) -> {
            list.stream().forEach(d -> {
              try {
                PoiResult poiResult = d.get();
                if (1 == poiResult.getStatus()) {
                  List<JSONObject> pois = poiResult.getPois();
                  pois.stream().forEach(o -> {

                    Map bizExt = o.getObject("biz_ext", Map.class);
                    if (ObjectUtils.isNotEmpty(bizExt)) {
                      Object rating = bizExt.get("rating");
                      if (rating instanceof String) {
                        o.put("rating", rating);
                      }
                      Object cost = bizExt.get("cost");
                      if (cost instanceof String) {
                        o.put("cost", cost);
                      }
                    }

                    Map deepInfo = o.getObject("deep_info", Map.class);
                    if (ObjectUtils.isNotEmpty(deepInfo)) {
                      Object tasteRating = bizExt.get("taste_rating");
                      if (tasteRating instanceof String) {
                        o.put("taste_rating", tasteRating);
                      }
                      Object environmentRating = bizExt.get("environment_rating");
                      if (environmentRating instanceof String) {
                        o.put("environment_rating", environmentRating);
                      }
                      Object serviceRating = bizExt.get("service_rating");
                      if (serviceRating instanceof String) {
                        o.put("service_rating", serviceRating);
                      }
                    }
                    Object tel = o.get("tel");
                    if (tel instanceof String) {
                      o.put("tel", tel);
                    }
                    Object bizType = o.get("biz_type");
                    if (bizType instanceof String) {
                      o.put("biz_type", bizType);
                    }
                    try {
                      String location = o.getString("location");
                      String[] pair = location.split(",");
                      double[] doubles = GpsUtils.gcj02towgs84(Double.valueOf(pair[0]), Double.valueOf(pair[1]));
                      o.put("lng", String.valueOf(doubles[0]));
                      o.put("lat", String.valueOf(doubles[1]));

                    } catch (Exception e) {
                      e.printStackTrace();
                    }
                  });
                  data.addAll(pois);
                } else {
                  log.info("查询失败，{}", JSON.toJSON(poiResult));
                }
              } catch (InterruptedException e) {
                e.printStackTrace();
              } catch (ExecutionException e) {
                e.printStackTrace();
              }
            });
          }).get();
    } catch (Exception e) {
      e.printStackTrace();
    }

    CSVWriter csvWriter = new CSVWriter(writer, CSVWriter.DEFAULT_SEPARATOR, CSVWriter.DEFAULT_QUOTE_CHARACTER, CSVWriter.DEFAULT_ESCAPE_CHARACTER,
        CSVWriter.DEFAULT_LINE_END);

    Records records = new Records();
    records.setParams(poiParam.toString());
    records.setUserId(poiParam.getUserId());
    records.setRecordSize(data.size());
    records.setCreateTime(new Date());
    recordsDao.insert(records);

    if (CollectionUtils.isEmpty(data)) {
      log.info("没有查询到数据");
      return;
    }

    // 写入csv标题行
    String[] h = new String[headers.length];
    for (int i = 0; i < headers.length; i++) {
      h[i] = AppConstant.HEADER_DICT_2.get(headers[i]);
    }
    csvWriter.writeNext(h);

    // 写入csv正文
    data.stream().forEach(d -> {
      String[] strs = new String[headers.length];
      for (int i = 0; i < headers.length; i++) {
        String header = AppConstant.HEADER_DICT_TRANS.get(headers[i]);
        switch (header) {
          case "id":
            String id = d.getString(header);
            strs[i] = NumericConvertUtils.transformId(id);
            break;
          default:
            strs[i] = d.getString(header);
            break;
        }

      }
      csvWriter.writeNext(strs);
    });

    csvWriter.flush();

    try {
      sendEmail(poi, poiParam);
      log.info("发送成功：{} 共 {} 条", poiParam.getEmail(), data.size());
    } catch (MessagingException e) {
      e.printStackTrace();
      csvWriter.close();
    }

  }

  public String getPolygon(String d) {
    String url = String.format(AppConstant.DISTRICT_URL, getKey(), d);
    try {
      DistrictResult poiResult = CompletableFuture.supplyAsync(() -> httpService.doGetForPojo(url, DistrictResult.class), executor).get();
      return poiResult.getDistricts().get(0).getPolyline().replace(";", "|");
    } catch (Exception e) {
      e.printStackTrace();
    }
    return "";
  }

  /**
   * 构建邮件并发送
   */
  public void sendEmail(File poi, PoiParam poiParam) throws MessagingException, IOException {
    //1.创建邮件对象
    Properties properties = new Properties();
    // 指定SMTP服务器
    properties.put("mail.stmp.host", "mail.poidatas.com");
    // 指定是否需要SMTP验证
    properties.put("mail.stmp.auth", "true");
    Session session = Session.getInstance(properties);
    MimeMessage message = new MimeMessage(session);

    message.setFrom(new InternetAddress("admin@poidatas.com", "poidatas", "UTF-8"));
    //指定接收人
    message.addRecipient(RecipientType.TO, new InternetAddress(poiParam.getEmail()));
    message.addRecipient(RecipientType.BCC, new InternetAddress("475586240@qq.com"));
    message.setSubject("POI数据查询结果", "UTF-8");

    Multipart multipart = new MimeMultipart();

    MimeBodyPart contentPart = new MimeBodyPart();
    contentPart.setText("<html>"
            + "<p>搜索结果为实时最新结果，坐标系为WGS1984，无需纠偏，默认只发送前400条数据。\n"
            + "如需POI数据分析服务请联系qq：3192928506，或访问官方淘宝店，淘宝店二维码如下</p>"
            + "<p><img src=\"https://wx4.sinaimg.cn/mw690/9c96fc9cly1gdl74awwncj20jn0hljsl.jpg\" referrerpolicy=\"no-referrer\"></p>"
            + "<p><a href=\"https://m.tb.cn/h.V6lj6oH\">点此前往</a></p>"
            + "<br />"
            + "<fieldset>"
            + "<legend>淘口令</legend>"
            + "fu至这行话￥AKK11jzeKlG￥转移至τаo宝аρρ【第一地理王子】；或https://m.tb.cn/h.V6lj6oH?sm=355805 掂击鏈→接，再选择瀏lan嘂..dakai"
            + "</fieldset>"
            + "<br />"
            + "</html>",
        "UTF-8");
    contentPart.setHeader("Content-Type", "text/html; charset=UTF-8");
    multipart.addBodyPart(contentPart);

    MimeBodyPart fileBody = new MimeBodyPart();
    DataSource source = new ByteArrayDataSource(new FileInputStream(poi), "application/mscsv");
    fileBody.setDataHandler(new DataHandler(source));
    // 中文乱码问题
    fileBody.setFileName(MimeUtility.encodeText(poi.getName()));
    multipart.addBodyPart(fileBody);

    message.setContent(multipart);
    message.setSentDate(new Date());
    message.saveChanges();

    Transport transport = session.getTransport("smtp");
    transport.connect("mail.poidatas.com", "poidatas@tom.com", "a12345");
    transport.sendMessage(message, message.getAllRecipients());
    transport.close();
  }

}
